/** \brief File implementing a Life's game cell
 *
 * This file contains the implementation of the class implementing a cell of
 * the Game of Life.
 *
 * @file Cell.cpp
 * @author Johan "Solo" Luisier
 * @date 2013/03/21
 */
#include "Cell.hpp"

#include "RuleData.hpp"

#include <QtCore/QDebug>

#include <algorithm>

#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>

using namespace std;
using namespace boost::lambda;

Cell::Cell( QObject* parent )
    : QObject( parent )
    , Neighbours()
    , BirthConditions()
    , SurvivalConditions()
    , CurrentStatus( Dead )
    , FutureStatus( Unknown )
{
}

Cell::~Cell()
{}


const QList< Cell* >& Cell::neighbours() const
{
    return Neighbours;
}

void Cell::addNeighbour( Cell* neighbour )
{
    if ( neighbour == 0 )
        return;
    if ( ! Neighbours.contains( neighbour ) )
        Neighbours.append( neighbour );
}

bool Cell::removeNeighbour( Cell* neighbour )
{
    return Neighbours.removeOne( neighbour );
}

void Cell::clearNeighbours()
{
    Neighbours.clear();
}

void Cell::setLifeRules( RuleData* ptr )
{
    BirthConditions = ptr -> birthConditions();
    SurvivalConditions = ptr -> survivalConditions();
}

/*
const QList< quint8 >& Cell::birthConditions() const
{
    return BirthConditions;
}

void Cell::setBirthConditions( const QList< quint8 >& conds )
{
    BirthConditions = conds;
}

void Cell::addBirthCondition( const quint8& bCond )
{
    if ( ! BirthConditions.contains( bCond ) )
        BirthConditions.append( bCond );
}

bool Cell::removeBirthCondition( const quint8& bCond )
{
    return BirthConditions.removeOne( bCond );
}

void Cell::clearBirthConditions()
{
    BirthConditions.clear();
}

const QList< quint8 >& Cell::survivalConditions() const
{
    return SurvivalConditions;
}

void Cell::setSurvivalConditions( const QList< quint8 >& conds )
{
    SurvivalConditions = conds;
}

void Cell::addSurvivalCondition( const quint8& sCond )
{
    if ( ! SurvivalConditions.contains( sCond ) )
        SurvivalConditions.append( sCond );
}

bool Cell::removeSurvivalCondition( const quint8& sCond )
{
    return SurvivalConditions.removeOne( sCond );
}

void Cell::clearSurvivalConditions()
{
    SurvivalConditions.clear();
}
*/
const Cell::Status& Cell::currentStatus() const
{
    return CurrentStatus;
}


#ifdef QT_DEBUG
void Cell::setCurrentStatus( const Status& status )
{
    CurrentStatus = status;
}
#endif

const Cell::Status& Cell::futureStatus() const
{
    return FutureStatus;
}

bool Cell::computeFutureStatus()
{
    if ( futureStatus() != Unknown )
        return false;

    quint8 AliveNbr( count_if( Neighbours.constBegin(), Neighbours.constEnd(),
                               bind< Status >( &Cell::currentStatus, _1 ) == Alive ) );

    qDebug() << "Number of alive neighbours(s):" << AliveNbr;

    if ( currentStatus() == Dead && BirthConditions.contains( AliveNbr ) )
        FutureStatus = Alive;
    else if ( currentStatus() == Alive && SurvivalConditions.contains( AliveNbr ) )
        FutureStatus = Alive;
    else
        FutureStatus = Dead;

    return true;
}

bool Cell::evolve()
{
    if ( futureStatus() == Unknown )
        return false;

    if ( CurrentStatus != FutureStatus )
    {
        CurrentStatus = FutureStatus;
        emit( flipped( this ) );
    }
    FutureStatus = Unknown;

    return true;
}

void Cell::toggleCurrentStatus()
{
    if ( currentStatus() == Alive )
        CurrentStatus = Dead;
    else
        CurrentStatus = Alive;

    emit( flipped( this ) );

    qDebug() << "New status:" << CurrentStatus;
}
